import sun.misc.Unsafe;

public class NoLackQueue<T> {

    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long headOffset;
    private static final long tailOffset;

    static {
        try {
            headOffset = unsafe.objectFieldOffset(NoLackQueue.class.getDeclaredField("head"));
            tailOffset = unsafe.objectFieldOffset(NoLackQueue.class.getDeclaredField("tail"));
        } catch (NoSuchFieldException e) {
            throw new Error(e);
        }
    }

    private volatile Node<T> head;
    private volatile Node<T> tail;

    public void put(T value) {
        Node<T> node = new Node<>();
        for (;;) {
            Node<T> tail = this.tail;
            if (tail == null) {
                if (compareAndSetHead(new Node<>())) {
                    this.tail = this.head;
                }
            } else {
                node.prev = tail;
                if (compareAndSetTail(tail, node)) {
                    tail.next = node;
                    return;
                }
            }
        }
    }

    private boolean compareAndSetHead(Node<T> update) {
        return unsafe.compareAndSwapObject(this, headOffset, null, update);
    }

    private boolean compareAndSetTail(Node<T> expect, Node<T> update) {
        return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
    }

    private static class Node<T> {
        T value;
        volatile Node<T> next;
        volatile Node<T> prev;
    }
}

